#pragma once

#include "../umlmodel_global.h"

#include <memory>
#include <vector>

#include "../umlcore/PartialElement.h"

using std::make_shared;
using std::shared_ptr;
using std::vector;

namespace uml {
class Classifier;

/// <summary>
/// RedefinableElement
/// A RedefinableElement is an element that, when defined in the context of a
/// Classifier, can be redefined more specifically or differently in the context of
/// another Classifier that specializes (directly or indirectly) the context
/// Classifier.
/// </summary>
class UMLMODEL_EXPORT RedefinableElement : public PartialElement {

public: // JsonSerializable override
    void fromJson(const QJsonObject& json, QStringList& errorList) override;
    void toJson(QJsonObject& json) override;

public: // Methods
    /// <summary>
    /// isConsistentWith
    /// The query isConsistentWith() specifies, for any two RedefinableElements in a
    /// context in which redefinition is possible, whether redefinition would be
    /// logically consistent. By default, this is false; this operation must be
    /// overridden for subclasses of RedefinableElement to define the consistency
    /// conditions.
    /// </summary>
    virtual bool isConsistentWith(shared_ptr<RedefinableElement> redefiningElement) const;

    /// <summary>
    /// isRedefinitionContextValid
    /// The query isRedefinitionContextValid() specifies whether the redefinition
    /// contexts of this RedefinableElement are properly related to the redefinition
    /// contexts of the specified RedefinableElement to allow this element to redefine
    /// the other. By default at least one of the redefinition contexts of this element
    /// must be a specialization of at least one of the redefinition contexts of the
    /// specified element.
    /// </summary>
    virtual bool isRedefinitionContextValid(shared_ptr<RedefinableElement> redefinedElement) const;

public: // Properties
    /// <summary>
    /// isLeaf getter
    /// Indicates whether it is possible to further redefine a RedefinableElement. If
    /// the value is true, then it is not possible to further redefine the
    /// RedefinableElement.
    /// </summary>
    bool isLeaf() const;

    /// <summary>
    /// isLeaf setter
    /// Indicates whether it is possible to further redefine a RedefinableElement. If
    /// the value is true, then it is not possible to further redefine the
    /// RedefinableElement.
    /// </summary>
    void setIsLeaf(bool value);

    /// <summary>
    /// redefinedElements getter
    /// The RedefinableElement that is being redefined by this element.
    /// </summary>
    vector<shared_ptr<RedefinableElement>>& redefinedElements();

    /// <summary>
    /// redefinitionContexts getter
    /// The contexts that this element may be redefined from.
    /// </summary>
    vector<shared_ptr<Classifier>>& redefinitionContexts();

private: // Fields
    /// <summary>
    /// isLeaf
    /// Indicates whether it is possible to further redefine a RedefinableElement. If
    /// the value is true, then it is not possible to further redefine the
    /// RedefinableElement.
    /// </summary>
    const static bool isLeaf_default_;
    bool isLeaf_= isLeaf_default_;

    /// <summary>
    /// redefinedElements
    /// The RedefinableElement that is being redefined by this element.
    /// </summary>
    vector<shared_ptr<RedefinableElement>> redefinedElements_;

    /// <summary>
    /// redefinitionContexts
    /// The contexts that this element may be redefined from.
    /// </summary>
    vector<shared_ptr<Classifier>> redefinitionContexts_;

};

} // namespace uml
